package com.hex.ds.hdtp.core.app.data.contrast.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.ds.hdtp.core.app.common.enums.CrossDbContrastInfo;
import com.hex.ds.hdtp.core.app.common.enums.CrossDbContrastScene;
import com.hex.ds.hdtp.core.app.data.contrast.dto.CrossDbContrastCommonDto;
import com.hex.ds.hdtp.core.app.data.contrast.dto.CrossDbContrastDataSqlDto;
import com.hex.ds.hdtp.core.app.data.contrast.dto.request.CrossDbContrastResultRequestDto;
import com.hex.ds.hdtp.core.app.data.contrast.service.ICrossDbContrastCommonService;
import com.hex.ds.hdtp.core.app.data.contrast.service.ICrossDbContrastResultService;
import com.hex.ds.hdtp.core.inf.data.contrast.service.impl.DataInfoSelectHandlerContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;


/**
 * @Package com.hex.ds.hdtp.core.app.data.contrast.service.impl
 * @ClassName CrossDbContrastCommonService
 * @Description 跨库比对公共服务
 * @Author jian.qiao
 * @Date 2023/10/8 11:58
 * @Version v1.0
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CrossDbContrastCommonService implements ICrossDbContrastCommonService {

    private final DataInfoSelectHandlerContext dataInfoSelectHandlerContext;

    private final ICrossDbContrastResultService crossDbContrastResultService;

    private static final String DATE8_FORMAT = "yyyyMMdd";

    /**
     * @Method queryContrastSceneDate <br>
     * @Param sceneType <br>
     * @Return java.lang.String <br>
     * @Description 获取比对场景对应时间<br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 11:58 <br>
     * @Version V1.0<br>
     */
    @Override
    public String queryContrastSceneDate(String sceneType) {
        CrossDbContrastScene crossDbContrastScene = CrossDbContrastScene.getByNameIgnoreCase(sceneType);
        if (crossDbContrastScene != null) {
            switch (crossDbContrastScene) {
                case TODAY:
                    return getToday();
                case YESTERDAY:
                    return getYesterday();
                case ENDOFLASTMONTH:
                    return getEndOfLastMonth();
                case FULL:
                    return "";
                default:
                    return "";
            }
        }
        return "";
    }

    /**
     * @Method partitionWhereSql <br>
     * @Param partitions
     * @Param date <br>
     * @Return java.lang.String <br>
     * @Description  分区字段where条件<br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 15:15 <br>
     * @Version V1.0<br>
     */
    @Override
    public String partitionWhereSql(List<String> partitions, String date) {
        if (CollUtil.isEmpty(partitions) || date.isEmpty()){
            return "";
        }
        StringBuilder partitionWhereSql = new StringBuilder();
        for (String partition : partitions) {
            partitionWhereSql.append(partition).append("='").append(date).append("'").append(" and ");
        }
        partitionWhereSql.setLength(partitionWhereSql.length() - 5);
        return String.format("WHERE %s",partitionWhereSql.toString().trim());
    }

    /**
     * @Method buildPartitionWhereSql <br>
     * @Param sourceType
     * @Param contrastType
     * @Param contrastInfo <br>
     * @Return com.hex.ds.hdtp.core.app.data.contrast.dto.CrossDbContrastDataSqlDto <br>
     * @Description 分区字段where <br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 16:05 <br>
     * @Version V1.0<br>
     */
    @Override
    public CrossDbContrastDataSqlDto buildPartitionWhereSql(String sourceType, String contrastType, CrossDbContrastCommonDto contrastInfo) throws SQLException {
        // 源与对比目标类型分区字段
        List<String> sourcePartitionField = dataInfoSelectHandlerContext.getDataInfoService(sourceType)
                .selectPartitionField(contrastInfo.getSourceCode(), contrastInfo.getSourceSchema(), contrastInfo.getSourceTable());
        List<String> targetPartitionField = dataInfoSelectHandlerContext.getDataInfoService(contrastType)
                .selectPartitionField(contrastInfo.getContrastCode(), contrastInfo.getContrastSchema(), contrastInfo.getContrastTable());
        String sourcePartitionWhereSql = "";
        String targetPartitionWhereSql = "";
        // 比对场景对应时间
        String partitionDate = queryContrastSceneDate(contrastInfo.getContrastScene());
        if (!StrUtil.equalsAnyIgnoreCase(sourceType, CrossDbContrastInfo.ORACLE.getName())) {
            sourcePartitionWhereSql = partitionWhereSql(sourcePartitionField,partitionDate);
        }
        if (!StrUtil.equalsAnyIgnoreCase(contrastType, CrossDbContrastInfo.ORACLE.getName())) {
            targetPartitionWhereSql = partitionWhereSql(targetPartitionField,partitionDate);
        }
        return new CrossDbContrastDataSqlDto().setSourcePartitionWhereSql(sourcePartitionWhereSql).setTargetPartitionWhereSql(targetPartitionWhereSql);
    }

    /**
     * @Method getToday <br>
     * @Return java.lang.String <br>
     * @Description 当天时间 <br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 11:59 <br>
     * @Version V1.0<br>
     */
    public String getToday() {
        LocalDate now = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE8_FORMAT);
        return now.format(formatter);
    }
    /**
     * @Method getYesterday <br>
     * @Return java.lang.String <br>
     * @Description 昨天时间<br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 11:59 <br>
     * @Version V1.0<br>
     */
    public String getYesterday(){
        String yesterday = DateUtil.format(DateUtil.yesterday(), DATE8_FORMAT);
        return yesterday;
    }

    /**
     * @Method getEndOfLastMonth <br>
     * @Return java.lang.String <br>
     * @Description 上月末<br>
     * @Author jian.qiao<br>
     * @Date 2023/10/8 11:59 <br>
     * @Version V1.0<br>
     */
    public String getEndOfLastMonth(){
        String lastMonthEnd = DateUtil.format(DateUtil.offset(DateUtil.beginOfMonth(DateUtil.date()), DateField.DAY_OF_MONTH, -1), DATE8_FORMAT);
        return lastMonthEnd;
    }
    /**
     * @param contrastCommon 跨库对比公共参数
     * @param runLogPkId     对比记录主键
     * @param contrastType   对比类型
     * @param contrastStatus 对比状态
     * @param errorMessage   对比异常信息
     * @Method addContrastResult
     * @Param
     * @Return void
     * @Description 新增跨库对比任务清单结果
     * @Author Wang zhihao
     * @Date 2023/7/31 20:09
     * @Version V1.0
     */
    public void addContrastResult(CrossDbContrastCommonDto contrastCommon, String runLogPkId, String contrastType, String contrastStatus, String errorMessage) {
        CrossDbContrastResultRequestDto crossDbContrastResultRequestDto = new CrossDbContrastResultRequestDto();
        crossDbContrastResultRequestDto.setContrastListPkId(contrastCommon.getContrastListPkId());
        crossDbContrastResultRequestDto.setContrastRunLogPkId(runLogPkId);
        crossDbContrastResultRequestDto.setContrastType(contrastType);
        crossDbContrastResultRequestDto.setContrastStatus(contrastStatus);
        crossDbContrastResultRequestDto.setErrorMessage(errorMessage);
        crossDbContrastResultService.add(crossDbContrastResultRequestDto);
    }
    /**
     * @Method findRootCause
     * @Param
     * @Param e
     * @Return java.lang.Throwable
     * @Description 辅助方法，递归查找根本原因
     * @Author xin.zhao
     * @Date 2023/12/6 9:23
     * @Version V1.0
     */
    public  Throwable findRootCause(Throwable e) {
        Throwable cause = e;
        while (cause.getCause() != null) {
            cause = cause.getCause();
        }
        return cause;
    }
}
